#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <getopt.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>

unsigned short port = 5050;
char ipaddr[16] = "127.0.0.1";
int child_count = 1;
int loop = 5000;
int buf_size = 1024;
typedef long long longlong_t;
typedef unsigned long long u_longlong_t;

void *thread_run (void *arg)
{
	int     sockfd , i, tolen;
	struct	sockaddr_in servaddr;
	struct  timeval tv = {5, 0};
    time_t  begin_time = 0;
    time_t  end_time = 0;
	
	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(port);
	inet_pton(AF_INET, ipaddr, &servaddr.sin_addr);
	tolen = sizeof (servaddr);

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (setsockopt (sockfd, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof (tv)) != 0)
	{
		fprintf (stderr, "%s\n", strerror (errno));
	}
	char *send_buf = (char *)malloc(buf_size); 
	char *recv_buf = (char *)malloc(buf_size);
	if(send_buf == NULL || recv_buf == NULL)
	{
		fprintf(stderr,"error:sendbuf[%p],recv_buf[%p]\n",send_buf,recv_buf);
		exit(0);
	} 
	int length = buf_size;
	*(int *)send_buf = length;
	*(int *)(send_buf+sizeof(int)) = getpid();
    
    begin_time = time(NULL);

	for (i = 0; i < loop; i++)
	{
		*(int *)(send_buf+2*sizeof(int)) = i;

		if (length != sendto (sockfd, send_buf, length, MSG_DONTWAIT, (const struct sockaddr*)&servaddr, tolen))
		{
			fprintf (stderr, "sendto error,pid=%d,count=%d\n",  getpid (), i);
			continue;
		}
recv_again:
		if (length != recvfrom (sockfd, recv_buf, length, 0, (struct sockaddr*)&servaddr,(socklen_t *) &tolen))
		{
			fprintf (stderr, "recvfrom error,pid=%d,count=%d,%s\n",  getpid (), i, strerror (errno));
			continue;
		}

		if (memcmp (recv_buf, send_buf, length) != 0)
		{
			fprintf (stderr, "strmcp error,send %s,recv %s\n",send_buf, recv_buf);
			goto recv_again;
		}
	}

    end_time = time (NULL);

    fprintf (stderr, "now[%lld], begin time[%lld] interval[%u]\n", (u_longlong_t)end_time, (u_longlong_t)begin_time, (u_int)(end_time - begin_time));

	return NULL;
}

int main (int argc, char* argv[])
{
	int c, i;
	pthread_t *thread_tid ;
	for (; (c = getopt (argc, argv, "p:c:i:l:b:")) != -1;)
	{
		switch (c)
		{
			case 'c':
				child_count = atoi (optarg);
				break;
			case 'p':
				port = atoi (optarg);
				break;
			case 'i':
				strncpy (ipaddr, optarg, sizeof (ipaddr) - 1);
				break; 
			case 'l':
				loop = atoi(optarg);	
				break; 
			case 'b':
				buf_size = atoi(optarg);	
				break; 
		}
	}

	thread_tid = (pthread_t*)calloc (child_count, sizeof (pthread_t));
	for (i = 0; i < child_count; i++)
		pthread_create (&thread_tid[i], NULL, &thread_run, NULL);

	for (i = 0; i < child_count; i++)
		pthread_join (thread_tid[i], NULL);

	return 0;
}
